package tpase.client.Controller;

import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import tpase.client.Handler.*;
import tpase.client.VO.*;
import tpase.util.Util;

import java.io.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

import static java.lang.Double.min;


public class MainController {
    //加密方案参数
    String uid = LoginController.uid;
    String password = LoginController.password;
    public static int t, n;
    // 是否 已经初始化
    public static boolean isSetup = true;
    public static boolean isDebug = true;
    public static boolean isFirstVerifyFinal = true;

//    public static Client client = LoginController.client ;


    //    //文件列表的列id
    public TableView<FileInfo> file_table;
    //
    public TableColumn<FileInfo, String> file_name;
    public TableColumn<FileInfo, String> file_time;
    public TableColumn<FileInfo, String> file_type;
    public TableColumn<FileInfo, String> file_size;
    public Label feedback_info;//刷新或上传的反馈信息
    public Pane warning;
    public Label mainTitleLabel;


    //文件列表
//    ObservableList<file_info> file_list = FXCollections.observableArrayList();

    public ContextMenu contextMenu = new ContextMenu();//右键菜单

    //右键菜单设置
    MenuItem uploadMenuItem = new MenuItem("     上传       ");
    MenuItem downloadMenuItem = new MenuItem("     下载       ");
    MenuItem download2MenuItem = new MenuItem("     下载到...    ");
    MenuItem refreshMenuItem = new MenuItem("     刷新       ");
    MenuItem deleteMenuItem = new MenuItem("     删除       ");

    String Default_folderPath = System.getProperty("user.dir") + "\\src\\main\\resources\\downloads\\" + uid;//默认下载地址（TPaSer-User下的Downloads文件夹  ）
    String uploadPath = System.getProperty("user.dir") + "/Save/" + LoginController.uid;//默认下载地址（TPaSer-User下的Downloads文件夹）


    @FXML
    private Parent rootLayout;
    @FXML
    public ProgressBar msg_progressbar;//进度条
    @FXML
    public TextArea console;//中间信息
    private double offsetX;
    private double offsetY;


    private static List<Address> serverList;
    private static Address storageServerAddress;

    private static String path = "src/main/resources/config";
    private static String publicParamPath = path + "/publicParam.json";
    private static PublicParam publicParam;
    private static Pairing pairing;
    private Object uploadLock = new Object();

    // 上传阶段 进度条每次增长的值
    final double uploadProgressBarNum = 0.1;

    static {
        pairing = Util.getPairing("src/main/resources/config/a.properties");
        publicParam = Util.jsonFileToObj(publicParamPath, PublicParam.class);
        t = publicParam.getMap().get("t")[0];
        n = publicParam.getMap().get("n")[0];
        String serverListJson = new String(publicParam.getMap().get("serverList"));
        serverList = Util.jsonToObject(serverListJson, ArrayList.class, Address.class);
        String storageServerPath = "src/main/resources/config/storageServerParameters.json";
        storageServerAddress = Util.jsonFileToObj(storageServerPath, Address.class);
    }

    // 刷新文件列表，用户请求 存储服务器 读取用户存储的文件列表
    public void refresh() {
        /*
            1. 向 Storage Server 发起查询文件请求 （参数 uid)。 Storage Server 向数据库查询，返回 List<FileInfo>
            2. 将List 渲染到 file_table
         */

        ObservableList<FileInfo> fileInfoList = FXCollections.observableArrayList();
        Util.processClientBootstrap(new ClientQueryFileInfoHandler(uid, fileInfoList), storageServerAddress);
        file_table.getItems().clear();

        //设置表格的列
        file_name.setCellValueFactory(new PropertyValueFactory<>("nameString"));
        file_time.setCellValueFactory(new PropertyValueFactory<>("timeString"));
        file_type.setCellValueFactory(new PropertyValueFactory<>("typeString"));
        file_size.setCellValueFactory(new PropertyValueFactory<>("sizeString"));
        file_table.setItems(fileInfoList);
        feedbackSuccess("刷新成功！");
    }

    private void feedbackSuccess(String str) {
        Platform.runLater(() -> {
            feedback_info.setTextFill(Color.GREEN);
            feedback_info.setText(str);
        });
    }

    private void feedbackError(String str) {
        feedback_info.setTextFill(Color.RED);
        feedback_info.setText(str);
    }


    // 关闭应用
    public void windowClose(ActionEvent actionEvent) {
        Stage stage = (Stage) rootLayout.getScene().getWindow();
        stage.close();
    }

    public void onMousePressed(MouseEvent mouseEvent) {
        offsetX = mouseEvent.getSceneX();
        offsetY = mouseEvent.getSceneY();
    }

    public void onMouseDragged(MouseEvent mouseEvent) {
        Stage stage = (Stage) rootLayout.getScene().getWindow();
        stage.setX(mouseEvent.getScreenX() - offsetX);
        stage.setY(mouseEvent.getScreenY() - offsetY);
        stage.setOpacity(0.9);
    }

    // 移动窗口位置，鼠标释放事件
    public void onMouseReleased(MouseEvent mouseEvent) {
        Stage stage = (Stage) rootLayout.getScene().getWindow();
        stage.setOpacity(1.0);
    }


    public void toUpload() throws IOException, InterruptedException, ClassNotFoundException {
        // 1 向服务器发起文件密钥生成请求

        // 2 计算文件密钥

        // 3 加密文件

        // 4 上传密文到存储服务器

        Stage stage = (Stage) rootLayout.getScene().getWindow();


        // 选择文件
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择文件目录");
        File file = fileChooser.showOpenDialog(stage);
        if (file == null) {
            return;
        }

        //读取文件
        byte[] bytesIn = readFile(file.getAbsolutePath());

        console.clear();

        Task task = createUploadFileWorker(file, bytesIn);
        msg_progressbar.progressProperty().unbind();
        msg_progressbar.progressProperty().bind(task.progressProperty());
        new Thread(task).start();

    }

    private void setProgressBarZero() {
        Platform.runLater(() -> {
            msg_progressbar.progressProperty().unbind();
            msg_progressbar.setProgress(0.0);
        });
    }

    private void setProgressBarFull() {
        msg_progressbar.progressProperty().unbind();
        msg_progressbar.setProgress(1.0);
    }

    /**
     * 用于实现上传过程中 进度条记录
     *
     * @param file
     * @param bytesIn
     * @return
     */
    private Task createUploadFileWorker(File file, byte[] bytesIn) {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                // 1 向服务器发起文件密钥生成请求

                // 2 计算文件密钥

                // 3 加密文件

                // 4 上传密文到存储服务器

                final int n = 7;
                int i = 1;


                consolePrintln("开始为您上传文件：%s", file.getName());
                updateProgress(i++, n);

                Ciphertext ciphertext = encFile(bytesIn, uid, password);

                if (ciphertext == null) {
                    System.out.println("加密失败！！");
                    updateProgress(0, n);
                    return false;
                }
                String ciphertextString = Util.toJson(ciphertext);

                consolePrintln("加密文件得到密文c = %s", Util.formatString(ciphertextString, 20));
                updateProgress(i++, n);

                String fileName = file.getName();

                String type = "";
                if (fileName.lastIndexOf(".") > 0) {
                    type = fileName.substring(fileName.lastIndexOf(".") + 1);
                }

                consolePrintln("【文件上传阶段】");
                updateProgress(i++, n);
                Util.processClientBootstrap(new ClientUploadFileHandler(uid, fileName, type, ciphertextString.getBytes()), storageServerAddress);


                consolePrintln("文件上传完成！");
                updateProgress(n, n);

                refresh();
                feedbackSuccess("上传文件完成！");

                return true;
            }
        };
    }

    /**
     * 进度条增加值 [0, 1.0]
     *
     * @param num
     */
    private void addProgressBar(double num) {
        double now = msg_progressbar.getProgress();
        double end = 1.0;
        // 防止溢出
        end = min(end, now + num);
        for (double i = now; i <= end; i += 0.0001) {
            msg_progressbar.setProgress(i);
        }
    }

    public void download(String path) throws IOException, ClassNotFoundException, InterruptedException {
        // 1 向 Storage Server 下载 密文
        // 2 在 Key Server 的协助下 生成 密钥
        // 3 解密 得到 明文
        // 4 存储明文到用户文件夹

        FileInfo selectedFile = file_table.getSelectionModel().getSelectedItem();//选中的文件

        console.clear();

        Task task = createDownloadFileWorker(selectedFile.getFid(), path, selectedFile.getFileName());
        msg_progressbar.progressProperty().unbind();
        msg_progressbar.progressProperty().bind(task.progressProperty());
        new Thread(task).start();



//        //反序列化读取密文文件
//        FileInputStream filein = new FileInputStream(selectedFile.getPath());
//        ObjectInputStream ois = new ObjectInputStream(filein);//对象输入流
//        Store_Ciphertext store_ciphertext = (Store_Ciphertext) ois.readObject();//读取对象
//        Ciphertext ciphertext = new Ciphertext();
//        ciphertext.setE(store_ciphertext.getE());
////        ciphertext.setCom_mFromBytes(store_ciphertext.getCom_m());
//        for (double i = 0; i < 0.05; i+=0.001) {msg_progressbar.setProgress(i);}
//
//        File tempfile = new File("src/main/resources/config/temp.txt");
//        //如果文件不存在，创建文件
//        if (!tempfile.exists()) {
//            tempfile.createNewFile();
//            //创建BufferedWriter对象并向文件写入内容
//            BufferedWriter bw = new BufferedWriter(new FileWriter(tempfile, true));
//            //向文件中写入内容
//            bw.write("开始为您下载文件："+selectedFile.getName()+"\n\n");
//            bw.flush();
//            bw.close();
//        }
//        for (double i = 0.05; i < 0.10; i+=0.001) {msg_progressbar.setProgress(i);}
//        // 4 解密文件
//        String  plaintext = Decodefile(ciphertext,uid,password);
//
//        for (double i = 0.10; i < 0.20; i+=0.001) {msg_progressbar.setProgress(i);}
//
//        BufferedReader reader = new BufferedReader(new FileReader(tempfile));
//        String tempString = null;
//        int line = 1;
//        // 一次读入一行，直到读入null为文件结束
//        console.clear();
//        console.setWrapText(false);
//        while ((tempString = reader.readLine()) != null) {
//            msg_progressbar.setProgress(0.20+0.8*line/34.0);
//            console.appendText(tempString+'\n');
//            console.positionCaret(console.getText().length());//将光标移动到文本末尾
//            System.out.println("line " + line + ": " + tempString);
//            line++;
//        }
//        filein.close();
//        reader.close();
//        tempfile.delete();
//        // 5 验证承诺
//
//
//
//        // 写文件
//        byte[] bytesOut = Base64.getDecoder().decode(plaintext);
//        writeFile(bytesOut,path+File.separator+selectedFile.getName());
//        feedback_info.setTextFill(Color.GREEN);
//        feedback_info.setText("文件成功下载到 "+path+" ！");

    }

    private Task createDownloadFileWorker(String fid, String path, String fileName) {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                // 1 向 Storage Server 下载 密文
                // 2 在 Key Server 的协助下 生成 密钥
                // 3 解密 得到 明文
                // 4 存储明文到用户文件夹

                final int n = 7;
                int i = 1;

                // 1 向 Storage Server 下载 密文
                Ciphertext ciphertext = new Ciphertext();
                Util.processClientBootstrap(new ClientDownloadFileHandler(fid, ciphertext), storageServerAddress);

                consolePrintln("【密文下载】");
                consolePrintln("密文下载完成，密文 c = %s", Util.formatString(ciphertext.toString()));
                updateProgress(i++, n);


                // 2 在 Key Server 的协助下 生成 密钥
                // 3 解密 得到 明文
                byte[] plaintext = decCiphertext(ciphertext, uid, password);
                updateProgress(i++, n);

                // 4 存储明文到用户文件夹
                Util.createDirectory(path);
                writeFile(plaintext,path + File.separator + fileName);
                consolePrintln("文件写入到位置 %s", path);
                updateProgress(i++, n);

                refresh();
                feedbackSuccess("下载文件完成！");
                updateProgress(n, n);
                return true;
            }
        };
    }

    private byte[] decCiphertext(Ciphertext ciphertext, String uid, String password) {
        Element com_m = pairing.getZr().newElementFromBytes(ciphertext.getCom_m());
        consolePrintln("文件承诺 H(m | r_m) = com_m = %s", com_m);

        consolePrintln("【密钥生成阶段】");
        Element key = KG(uid, password, com_m);
        if (key == null) {
            consolePrintln("密钥生成失败！");
            return null;
        }
        consolePrintln("密钥生成成功，密钥key = %s", Util.formatString(key.toString()));

        consolePrintln("【解密阶段】");
        byte[] m_plus_rmBytes = Util.decrypt(key.toString(), ciphertext.getE());

        byte[] mBytes = Util.split(m_plus_rmBytes)[0];
        byte[] r_mBytes = Util.split(m_plus_rmBytes)[1];

        Element com_m2 = Util.hash(pairing.getZr(), Util.mergeArrays(mBytes, r_mBytes));

        consolePrintln("验证密文中 com_m = %s 和 \n H(m | r) = %s \n 是否相等", Util.formatString(com_m.toString()), Util.formatString(com_m2.toString()));

        if (!com_m2.equals(com_m)) {
            consolePrintln("解密错误！");
            return null;
        }
        consolePrintln("解密完成，明文 = %s", Util.formatString(Arrays.toString(mBytes)));


        return mBytes;
    }

    public void delete() {
        FileInfo fileInfo = file_table.getSelectionModel().getSelectedItem();//选中的文件

        Util.processClientBootstrap(new ClientDeleteFileHandler(fileInfo.getFid()), storageServerAddress);
        refresh();

        feedbackSuccess("删除文件 " + fileInfo.getFileName() + " 成功！");
    }


    //页面初始化
    public void initialize() {
        mainTitleLabel.setText("TPaSE · " + uid);
        refresh();
        feedbackSuccess("登录成功！！！");
        //右键菜单设置
        contextMenu.getItems().addAll(uploadMenuItem, downloadMenuItem, download2MenuItem, refreshMenuItem, deleteMenuItem);
        file_table.setContextMenu(contextMenu);
        setMenuClick();


        console.setWrapText(false);
        console.textProperty().addListener(new ChangeListener<Object>() {
            @Override
            public void changed(ObservableValue<?> observable, Object oldValue, Object newValue) {
                console.setScrollTop(Double.MAX_VALUE); //this will scroll to the bottom);
                //use Double.MIN_VALUE to scroll to the top
            }
        });

    }


    //设置菜单点击事件
    public void setMenuClick() {

        uploadMenuItem.setOnAction(event -> {
            try {
                toUpload();
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        });
        downloadMenuItem.setOnAction(event -> {

            File folderPath = new File(Default_folderPath);
            if (!folderPath.exists()) {
                folderPath.mkdir();//没有此文件夹就创建文件夹
            }
            try {
                download(Default_folderPath);
            } catch (IOException | ClassNotFoundException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        download2MenuItem.setOnAction(event -> {
            //指定下载目录
            Stage stage = (Stage) rootLayout.getScene().getWindow();
            DirectoryChooser directoryChooser = new DirectoryChooser();
            directoryChooser.setTitle("选择保存目录");
            File folderPath = directoryChooser.showDialog(stage);

            if (folderPath == null) {
                return;
            }


            try {
                download(folderPath.getAbsolutePath());
            } catch (IOException | InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        });
        refreshMenuItem.setOnAction(event -> {
            refresh();
        });
        deleteMenuItem.setOnAction(event -> {

            //delete();
            //javafx弹出警告窗口
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setTitle("警告");
            alert.setHeaderText("确定要删除文件 " + file_table.getSelectionModel().getSelectedItem().getFileName() + " 吗？");
            Optional<ButtonType> result = alert.showAndWait();
            if (result != null && "Optional.empty".equals(result.toString())) {
                feedback_info.setText("已取消删除！");
            } else if (result.get() == ButtonType.OK) {
                delete();
            }

        });
    }

    public static void setup() throws InterruptedException {
//        if (isSetup == false) {
//            Setup.getSetup().start();
//        }
//        //读取公共参数
//        String setupPath = "src/main/resources/config/setup/parameters.json";
//        SetupParam setupParam = org.tpase.util.Util.jsonFileToObj(setupPath, SetupParam.class);
//        t = setupParam.getT();
//        n = setupParam.getN();
//
//        if (isDebug) {
//            System.out.printf("总服务器数量：%s，门限服务器数量：%s \n", n, t);
//        }
//
//
//        String serverPath = "src/main/resources/config/servers/server";
//        List<Server> serverLists = new ArrayList<>();
//        for (int i = 0; i < n; i++) {
//            String paramPath = serverPath + i;
//            Server server = new Server(paramPath, isDebug);
//            if (isSetup == false) {
//                server.setup();
//            }
//            serverLists.add(server);
//        }
//
//        if (isSetup == false) {
//            Thread.sleep(2000);
//        }
//
//        //多线程并行计算
//        for (int i = 0; i < n; i++) {
//            Server server = serverLists.get(i);
//            new Thread(server::start).start();
//        }
    }


    private Ciphertext encFile(byte[] m, String uid, String password) {
        Element r_m = pairing.getZr().newRandomElement();
        // com_m = H(m, r_m)
        Element com_m = Util.hash(pairing.getZr(), Util.mergeArrays(m, r_m.toBytes()));

        consolePrintln("随机值 r_m = %s", r_m);
        consolePrintln("文件承诺 H(m | r_m) = com_m = %s", com_m);

        consolePrintln("【密钥生成阶段】");
        Element key = KG(uid, password, com_m);
        if (key == null) {
            consolePrintln("密钥生成失败！");
            return null;
        }
        consolePrintln("密钥生成成功，密钥key = %s", Util.formatString(key.toString()));

        consolePrintln("【加密阶段】");
        // 这里为 [ plaintext.length, plaintext, r_m.length, r_m ]
        byte[] m_plus_rm = Util.combine(m, r_m.toBytes());
        byte[] e = Util.encrypt(key.toString(), m_plus_rm);

        return new Ciphertext(e, com_m.toBytes());
    }

    private void consolePrintln(String template, Object... values) {
        String str = String.format(template, values);
        Platform.runLater(() -> {
            console.appendText(str + "\n\n");
        });
    }

    private Element KG(String uid, String password, Element com_m) {
        List<Element> Y_1iList = new CopyOnWriteArrayList<>();
        List<byte[]> c_Y2iList = new CopyOnWriteArrayList<>();
        List<VerifyInfo> verifyList = new CopyOnWriteArrayList<>();
        List<Element> xServerList = new CopyOnWriteArrayList<>();

        // 数量为t的集合，用于计算秘密共享密钥
        List<Address> thresholdList = Util.getThresholdList(serverList, t);
        // 发送给服务器 计算 lambda_{0, i, T}
        List<byte[]> idList = Util.getIdList(thresholdList);

        // x_pwd = H_1(pwd)^{r_{pwd}}
        Element r_pwd = pairing.getZr().newRandomElement();
        Element x_pwd = Util.hash(pairing.getG1(), password).powZn(r_pwd);

        Object lock = new Object();


        for (int i = 0; i < t; i++) {
            Address serverAddress = thresholdList.get(i);

            consolePrintln("发送 uid = %s, x_pwd = %s, com_m = %s 给 [密钥服务器 %s]", uid, Util.formatString(x_pwd.toString()), Util.formatString(com_m.toString()), serverAddress.toString());

            new Thread(() -> {
                Util.processClientBootstrap(new ClientKGHandler(pairing, uid, x_pwd, com_m, idList, Y_1iList, c_Y2iList, verifyList, lock, t, xServerList), serverAddress);
            }).start();
        }

        synchronized (lock) {
            while (Y_1iList.size() < t || c_Y2iList.size() < t) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            lock.notifyAll();
        }

        consolePrintln("获取到密钥服务器的响应。");


        Element H_2_uid = Util.hash(pairing.getG2(), uid);
        // e(x_pwd, H_2(uid))
        Element e_xpwd_H2uid = pairing.pairing(x_pwd, H_2_uid);
        Element gT = pairing.getGT().newElementFromBytes(publicParam.getMap().get("gT"));

        if (!isFirstVerifyFinal) {
            if (!verifyY1i(verifyList, e_xpwd_H2uid, gT)) {
                System.out.println("Y_1i verify fail");
                return null;
            }
        }

        // get Y1
        Element Y_1 = Util.getY1(Y_1iList, r_pwd, xServerList, pairing);


        consolePrintln("计算得到用户认证信息Y_1 = %s", Util.formatString(Y_1.toString()));

        List<Element> Y_2List = new ArrayList<>();
        for (int i = 0; i < c_Y2iList.size(); i++) {
            String Y_1_i = Y_1.toString() + verifyList.get(i).getX().toString();
            Element auth_uid_i = Util.hash(pairing.getZr(), Y_1_i);
            byte[] Y_2Bytes = Util.decrypt(auth_uid_i.toString(), c_Y2iList.get(i));
            Y_2List.add(pairing.getG2().newElementFromBytes(Y_2Bytes));
        }

        List<Element> gammaList = getGammaList(verifyList);
        Element g1 = pairing.getG1().newElementFromBytes(publicParam.getMap().get("g1"));
        Element H_4_uid_comm = Util.hash(pairing.getG2(), uid + com_m.toString());

        // verify Y_2i
        if (!isFirstVerifyFinal) {
            if (!verifyY2i(Y_2List, gammaList, g1, H_4_uid_comm, verifyList)) {
                System.out.println("Y_2i verify fail");
                return null;
            }
        }
        Element Y2 = Util.getY2(Y_2List, xServerList, pairing);


        consolePrintln("计算得到文件密钥Y_2 = %s", Util.formatString(Y2.toString()));

        if (isFirstVerifyFinal) {
            Element gamma_s = pairing.getG1().newElementFromBytes(publicParam.getMap().get("gamma_s"));
            if (verifyY2(gamma_s, H_4_uid_comm, g1, Y2)) {
                return Y2;
            }
            if (!verifyY1i(verifyList, e_xpwd_H2uid, gT)) {
                System.out.println("Y_1i verify fail");
                return null;
            }
            if (!verifyY2i(Y_2List, gammaList, g1, H_4_uid_comm, verifyList)) {
                System.out.println("Y_2i verify fail");
                return null;
            }
        }


        consolePrintln("验证计算结果正确");

        return Y2;
    }

//    private static String Decodefile(Ciphertext ciphertext,String uid,String password) throws InterruptedException {
//        setup();
//        String clientPath = "src/main/resources/config/clients/client0";
//        client = new Client(clientPath, uid, password, isDebug, isFirstVerifyFinal);
//        if (isSetup == false) {
//            client.setup();
//        }
//        String decResult = client.dec(ciphertext);
//        return decResult;
//    }

    private static boolean verifyY2i(List<Element> y2List, List<Element> gammaList, Element g1, Element h4UidComm, List<VerifyInfo> verifyList) {
        for (int i = 0; i < y2List.size(); i++) {
            Element Y_2i = y2List.get(i);
            Element gamma_si = gammaList.get(i);
            if (!pairing.pairing(gamma_si, h4UidComm).equals(pairing.pairing(g1, Y_2i))) {
                Element x = verifyList.get(i).getX();
                System.out.printf("server[%s] returns the wrong computation", x);
                return false;
            }
        }
        return true;
    }

    private static boolean verifyY2(Element gamma_s, Element H_4_uid_comm, Element g1, Element Y2) {
        return pairing.pairing(gamma_s, H_4_uid_comm).equals(pairing.pairing(g1, Y2));
    }

    private static List<Element> getGammaList(List<VerifyInfo> list) {
        List<Element> gammaList = new ArrayList<>();
        Map<String, byte[]> map = publicParam.getMap();
        for (int i = 0; i < list.size(); i++) {
            String x = list.get(i).getX().toString();
            gammaList.add(pairing.getG1().newElementFromBytes(map.get("gamma_s" + x)));
        }
        return gammaList;
    }

    private static boolean verifyY1i(List<VerifyInfo> verifyList, Element eXpwdH2uid, Element gT) {
        for (VerifyInfo verifyInfo : verifyList) {
            Element x = verifyInfo.getX();
            Element gamma_sti = pairing.getGT().newElementFromBytes(publicParam.getMap().get("gamma_ts" + x.toString()));
            verifyInfo.setW(eXpwdH2uid);
            verifyInfo.setG(gT);
            verifyInfo.setGamma(gamma_sti);
            verifyInfo.setPairing(pairing);
            if (!verifyInfo.verify()) {
                System.out.printf("server[%s] returns the wrong computation", x);
                return false;
            }
        }
        return true;
    }


    public static byte[] readFile(String filePath) throws IOException {
        FileInputStream fis = new FileInputStream(filePath);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        fis.close();
        return bos.toByteArray();
    }

    public static void writeFile(byte[] data, String filePath) throws IOException {
        System.out.println(filePath);
        FileOutputStream fos = new FileOutputStream(filePath);
        fos.write(data);
        fos.close();
    }


}
